//  Copyright (c) 2011 M.A. (Thijs) van den Berg, http://sitmo.com/
//
//  Use, modification and distribution are subject to the MIT Software License. 
// (See accompanying file LICENSE.txt or copy at http://www.bmlib.org/LICENSE.txt)
//
//Low-Fat Spreads by K. Ravindran, RISK, Oct 1993.
#include "_GenSpread.h"
#include "_NormDist.h"
#include "_GenBlackScholes.h"
#include <cmath>

bool GenSpread::check_parameters()
{
	valid_parameters = false;

	if (c<-1.0) return false;
	if (c>1.0) return false;
	if (S2<=0.0) return false;	// float
	if (v2<=0.0) return false;	// float

	double r1 = r-Y;
	double r2 = r-Y2;
	if (X <= - S2 * exp(v2 * sqrt(t) * -5.0 + (r - r2 - 0.5 * v2 * v2) * t)) return false;

	return OptionModel::check_parameters();
}

bool GenSpread::price(double &ret) const
{
	if (!valid_parameters) return false;

const double x[32] = {
	-4.98631930924741,
	-4.92805755772634,
	-4.82381127793753,
	-4.6745303796887,
	-4.48160577883026,
	-4.24683806866285,
	-3.97241897983971,
	-3.66091059370145,
	-3.31522133465108,
	-2.93857878620381,
	-2.53449954466115,
	-2.10675638065318,
	-1.65934301141064,
	-1.19643681126069,
	-0.722359807913982,
	-0.241538328438692,
	0.241538328438692,
	0.722359807913982,
	1.19643681126069,
	1.65934301141064,
	2.10675638065318,
	2.53449954466115,
	2.93857878620381,
	3.31522133465108,
	3.66091059370145,
	3.97241897983971,
	4.24683806866285,
	4.48160577883026,
	4.6745303796887,
	4.82381127793753,
	4.92805755772634,
	4.98631930924741
	};
const double w[32] = {
	0.035093050047348,
	0.0813719736545292,
	0.126960326546311,
	0.171369314565107,
	0.214179490111091,
	0.254990296311873,
	0.293420467392676,
	0.329111113881808,
	0.361728970544243,
	0.390969478935351,
	0.416559621134734,
	0.438260465022019,
	0.455869393478819,
	0.469221995404022,
	0.478193600396374,
	0.482700442573639,
	0.482700442573639,
	0.478193600396374,
	0.469221995404022,
	0.455869393478819,
	0.438260465022019,
	0.416559621134734,
	0.390969478935351,
	0.361728970544243,
	0.329111113881808,
	0.293420467392676,
	0.254990296311873,
	0.214179490111091,
	0.171369314565107,
	0.126960326546311,
	0.0813719736545292,
	0.035093050047348
	};

	double a = 1.0;
	double b = 1.0;
	double p;
	GBS gbs("C", S, v, Y, r, t, X, 0.00);
	ret = 0;
	for (int k=0; k<32; ++k)
	{
		double r1 = r-Y;
		double r2 = r-Y2;
		double S_ = a * S * exp(c * v * sqrt(t) * x[k] - 0.5*v*v * c*c * t);
		double X_ = b * S2 * exp(v2 * sqrt(t) * x[k] + (r - r2 - 0.5 * v2 * v2) * t) + X;
		double v_ = v * sqrt(1.0 - c*c);

		gbs.S = S_;
		gbs.X = X_;
		gbs.v = v_;
		gbs.price(p);
		ret += w[k] * p * n(x[k]); /// standard normal density function
	}

	if (OptionType == eOptionTypes::eOptionType_Put) {
		ret -= exp(-r*t)*(S*exp(Y*t)-S2*exp(Y2*t)-X);
	}
	return true;
}
